`timescale 1 ns / 1 ps


module multipb_top
  (
	input  wire        clk_50,
	input  wire        rst,
	input  wire  [3:0] switches,
	output reg   [7:0] leds
);

	//******************************************************************//
	// declarations                                                     //
	//******************************************************************//
	wire write_strobe;
	wire read_strobe;
	wire clk0,clk1,clk2,clk3;
	wire lock0,lock1,lock2,lock3;
	wire clkp0,clkp1,clkp2,clkp3;
	
	wire [1:0] sel;
	wire [7:0] port_id;
	wire [7:0] out_port;
	reg  [7:0] in_port;
  
	reg  clk;
	wire [3:0]counter_next;
	reg  [3:0]counter_reg;

	always @(posedge clk_50,posedge rst) 
	begin
		if (rst)
		begin
			counter_reg = 0;
			clk = 0;
		end
		else
		begin 
			counter_reg = counter_next;
			if (counter_reg==10)
			begin
				clk = ~clk;
				counter_reg = 0;
			end
		end
	end
	
	assign counter_next = counter_reg+1;


	//******************************************************************//
	// Instantiate PicoBlaze 0 and its instruction ROM.                 //
	//******************************************************************//
	wire    [9:0] address_0;
	wire   [17:0] instruction_0;
	wire    [7:0] port_id_0;
	wire    [7:0] out_port_0;
	wire    [7:0] in_port_0;
	wire          write_strobe_0;
	wire          read_strobe_0;
	wire          interrupt_0;
	wire          interrupt_ack_0;

	assign interrupt_0 = 1'b0;
	assign clkp0 = clk0 & lock0;

	kcpsm3 PicoBlaze0 (
		.address(address_0),
		.instruction(instruction_0),
		.port_id(port_id_0),
		.write_strobe(write_strobe_0),
		.out_port(out_port_0),
		.read_strobe(read_strobe_0),
		.in_port(in_port_0),
		.interrupt(interrupt_0),
		.interrupt_ack(interrupt_ack_0),
		.reset(rst),
		.clk(clkp0));

	multpb_0 rom_0 (
		.address(address_0),
		.instruction(instruction_0),
		.clk(clkp0));

  //******************************************************************//
  // Instantiate PicoBlaze 1 and its instruction ROM.                 //
  //******************************************************************//
  wire    [9:0] address_1;
  wire   [17:0] instruction_1;
  wire    [7:0] port_id_1;
  wire    [7:0] out_port_1;
  wire    [7:0] in_port_1;
  wire          write_strobe_1;
  wire          read_strobe_1;
  wire          interrupt_1;
  wire          interrupt_ack_1;

  assign interrupt_1 = 1'b0;
  assign clkp1 = clk1 & lock1;
	
  kcpsm3 PicoBlaze1 (
    .address(address_1),
    .instruction(instruction_1),
    .port_id(port_id_1),
    .write_strobe(write_strobe_1),
    .out_port(out_port_1),
    .read_strobe(read_strobe_1),
    .in_port(in_port_1),
    .interrupt(interrupt_1),
    .interrupt_ack(interrupt_ack_1),
    .reset(rst),
    .clk(clkp1));

  multpb_1 rom_1 (
    .address(address_1),
    .instruction(instruction_1),
    .clk(clkp1));
  
  //******************************************************************//
  // Instantiate PicoBlaze 2 and its instruction ROM.                 //
  //******************************************************************//
  wire    [9:0] address_2;
  wire   [17:0] instruction_2;
  wire    [7:0] port_id_2;
  wire    [7:0] out_port_2;
  wire    [7:0] in_port_2;
  wire          write_strobe_2;
  wire          read_strobe_2;
  wire          interrupt_2;
  wire          interrupt_ack_2;

  assign interrupt_2 = 1'b0;
  assign clkp2 = clk2 & lock2;

  kcpsm3 PicoBlaze2 (
    .address(address_2),
    .instruction(instruction_2),
    .port_id(port_id_2),
    .write_strobe(write_strobe_2),
    .out_port(out_port_2),
    .read_strobe(read_strobe_2),
    .in_port(in_port_2),
    .interrupt(interrupt_2),
    .interrupt_ack(interrupt_ack_2),
    .reset(rst),
    .clk(clkp2));

  multpb_2 rom_2 (
    .address(address_2),
    .instruction(instruction_2),
    .clk(clkp2));
  
  //******************************************************************//
  // Instantiate PicoBlaze 3 and its instruction ROM.                 //
  //******************************************************************//
  wire    [9:0] address_3;
  wire   [17:0] instruction_3;
  wire    [7:0] port_id_3;
  wire    [7:0] out_port_3;
  wire    [7:0] in_port_3;
  wire          write_strobe_3;
  wire          read_strobe_3;
  wire          interrupt_3;
  wire          interrupt_ack_3;

  assign interrupt_3 = 1'b0;
  assign clkp3 = clk3 & lock3;  

  kcpsm3 PicoBlaze3 (
    .address(address_3),
    .instruction(instruction_3),
    .port_id(port_id_3),
    .write_strobe(write_strobe_3),
    .out_port(out_port_3),
    .read_strobe(read_strobe_3),
    .in_port(in_port_3),
    .interrupt(interrupt_3),
    .interrupt_ack(interrupt_ack_3),
    .reset(rst),
    .clk(clkp3));

  multpb_3 rom_3 (
    .address(address_3),
    .instruction(instruction_3),
    .clk(clkp3));

  //******************************************************************//
  // IN/OUT arbiter                                                   //
  //******************************************************************//
	arbiter ioArbiter(
		.clk(clk),
		.reset(rst),
	   .wr0(write_strobe_0),
		.wr1(write_strobe_1),
		.wr2(write_strobe_2),
		.wr3(write_strobe_3),
		.rd0(read_strobe_0),
		.rd1(read_strobe_1),
		.rd2(read_strobe_2),
		.rd3(read_strobe_3),
		.sel(sel),
		.clk0(clk0),
		.clk1(clk1),
		.clk2(clk2),
		.clk3(clk3),
		.wr(write_strobe),
		.rd(read_strobe)
	);

  //******************************************************************//
  // Mutex controller                                                 //
  //******************************************************************//
	mutex mutex_controller(
		.clk(clk),
		.reset(rst),
		.wr(write_strobe),
		.pid(sel),
		.port_id(port_id),
		.out_port(out_port),
		.l0(lock0),
		.l1(lock1),
		.l2(lock2),
		.l3(lock3)
	);

	//******************************************************************//
	// MUX port_id                                                      //
	//******************************************************************//
	mux mux_port_id(
		.sel(sel),
		.in0(port_id_0),
		.in1(port_id_1),
		.in2(port_id_2),
		.in3(port_id_3),
		.out(port_id)
	);

	//******************************************************************//
	// MUX out_port                                                     //
	//******************************************************************//
	mux mux_out_port(
		.sel(sel),
		.in0(out_port_0),
		.in1(out_port_1),
		.in2(out_port_2),
		.in3(out_port_3),
		.out(out_port)
	);

	//******************************************************************//
	// in_port                                                          //
	//******************************************************************//
	assign in_port_0 = in_port;
	assign in_port_1 = in_port;	
	assign in_port_2 = in_port;
	assign in_port_3 = in_port;
	
  //******************************************************************//
  // Implement output ports.                                          //
  // 00h: LED data output port                                        //
  //******************************************************************//
  always @(posedge clk,posedge rst)
    begin
	 if (rst)
		leds <= 0;
    else if (write_strobe)
    begin
      if (port_id == 8'h02) leds[0] <= out_port[0];
      if (port_id == 8'h03) leds[1] <= out_port[0];
      if (port_id == 8'h04) leds[2] <= out_port[0];
      if (port_id == 8'h05) leds[3] <= out_port[0];
      if (port_id == 8'h06) leds <= out_port;		
    end
  end

  //******************************************************************//
  // Implement input ports.                                           //
  // 00h: LED data output port readback                               //
  // 01h: Switch data input port                                      //
  //******************************************************************//
  always @*
  begin
    case (port_id)
      8'h01: in_port <= {4'b0000,switches};
      8'h02: in_port <= {7'b0000_000,leds[0]};
      8'h03: in_port <= {7'b0000_000,leds[1]};
      8'h04: in_port <= {7'b0000_000,leds[2]};
      8'h05: in_port <= {7'b0000_000,leds[3]};
      8'h06: in_port <= leds;
      default: in_port <= 8'h00;
    endcase
	 $display("port=%d inport=%d",port_id,in_port);
  end

  //******************************************************************//
  //   CHIPSCOPE                                                      //
  //******************************************************************//
//	wire [35:0] ILA_control;
//  
//	controller chipscope_controller (
//		.CONTROL0(ILA_control) // INOUT BUS [35:0]
//	);
//  
//	ILA chipscope_ila (
//		.CONTROL(ILA_control), // INOUT BUS [35:0]
//		.CLK(clk_50), // IN
//		.TRIG0({write_strobe_3,write_strobe_2,write_strobe_1,write_strobe_0, // 4 ports
//		        read_strobe_3,read_strobe_2,read_strobe_1,read_strobe_0,     // 4 ports
//				  4'b0000,
//				  leds}) // IN BUS [19:0]
//	);

  
  
endmodule